package com.ruoyi.common.utils.file;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.StorageClass;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;
import lombok.SneakyThrows;
import org.aspectj.util.FileUtil;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class TXOSSUtils {

    private static String parserCosRegion(String cosRegion) {
        String[] split = cosRegion.split("\\.");
        for (String text : split) {
            if (text.startsWith("ap")) {
                return text;
            }
        }
        return null;
    }

    // 创建 COSClient 实例，这个实例用来后续调用请求
    static COSClient createCOSClient(String secretId, String secretKey, String cosRegion) {
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();


        // 设置 bucket 的地域
        // COS_REGION 请参见 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion(new Region(parserCosRegion(cosRegion)));


        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本，建议设置使用 https 协议
        // 5.6.54 及更高版本，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);


        // 设置 socket 读取超时，默认 30s
        clientConfig.setSocketTimeout(30 * 1000);
        // 设置建立连接超时，默认 30s
        clientConfig.setConnectionTimeout(30 * 1000);

        // 如果需要的话，设置 http 代理，ip 以及 port
//        clientConfig.setHttpProxyIp("httpProxyIp");
//        clientConfig.setHttpProxyPort(80);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }

    static void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(true);
    }

    // 创建 TransferManager 实例，这个实例用来后续调用高级接口
    static TransferManager createTransferManager(String secretId, String secretKey, String cosRegion) {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient(secretId, secretKey, cosRegion);
        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);
        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5 * 1024 * 1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1 * 1024 * 1024);
        transferManager.setConfiguration(transferManagerConfiguration);


        return transferManager;
    }


//    @SneakyThrows
//    public static void main(String[] args) throws FileNotFoundException {
//        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
//        // 详细代码参见本页：高级接口 -> 创建 TransferManager
//        String secretId = "AKIDBHID3ikjYHn4BF9pKeopjXDhDbs8C9wm";
//        String secretKey = "rV1woXGuQwLk5LSNG8sQvMpHe5TqEYrJ";
    //        String cosRegion = "https://xiangcunmenhu-1302124406.cos.ap-nanjing.myqcloud.com";
//        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
//        String bucketName = "xiangcunmenhu-1302124406";
//        // 对象键(Key)是对象在存储桶中的唯一标识。
//        String key = "test/FileUtils.java";
//
//        // 本地文件路径
//        String localFilePath = "E:\\java_workspack\\material\\ruoyi-common\\src\\main\\java\\com\\ruoyi\\common\\utils\\file\\FileUploadUtils.java";
//
//        System.out.println(uploadOneFile(secretId, secretKey, cosRegion, bucketName, key, FileUtil.readAsByteArray(new File(localFilePath))));
//
//    }

    public static String uploadOneFile(String secretId, String secretKey, String cosRegion, String bucketName, String key, byte[] bytes) {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(bytes.length);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, objectMetadata);


        // 设置存储类型（如有需要，不需要请忽略此行代码）, 默认是标准(Standard), 低频(standard_ia)
        // 更多存储类型请参见 https://cloud.tencent.com/document/product/436/33417
        //        putObjectRequest.setStorageClass(StorageClass.Standard_IA);
        TransferManager transferManager = createTransferManager(secretId, secretKey, cosRegion);
        UploadResult uploadResult = null;
        try {
            // 高级接口会返回一个异步结果Upload
            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回 UploadResult, 失败抛出异常
            Upload upload = transferManager.upload(putObjectRequest);
            uploadResult = upload.waitForUploadResult();
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        // 确定本进程不再使用 transferManager 实例之后，关闭即可
        // 详细代码参见本页：高级接口 -> 关闭 TransferManager
        shutdownTransferManager(transferManager);
        return cosRegion + "/" + uploadResult.getKey();
    }

}
